// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Custom/Forward Rendering"
{
    Properties
    {
        // specular gloss
        _EdgeThickness ("Outline Thickness", Float) = 1

        // Colors
        _Color ("Color", Color) = (1, 1, 1, 1)
        _HColor ("Highlight Color", Color) = (0.8, 0.8, 0.8, 1.0)
        _SColor ("Shadow Color", Color) = (0.2, 0.2, 0.2, 1.0)
        
        // texture
        _MainTex ("Main Texture", 2D) = "white" { }
        _ShadowTex ("Shadow Texture", 2D) = "white" { }
        _FalloffSampler ("Falloff Control", 2D) = "white" {}
        _RimLightSampler ("RimLight Control", 2D) = "white" {}

        
        // ramp
        _ToonSteps ("Steps of Toon", range(1, 9)) = 2
        _RampThreshold ("Ramp Threshold", Range(0.1, 1)) = 0.5
        _RampSmooth ("Ramp Smooth", Range(0, 1)) = 0.1
        
        // specular
        _SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
        _SpecSmooth ("Specular Smooth", Range(0, 1)) = 0.1
        _Shininess ("Shininess", Range(0.001, 10)) = 0.2
        
        // rim light
        _RimColor ("Rim Color", Color) = (0.8, 0.8, 0.8, 0.6)
        _RimThreshold ("Rim Threshold", Range(0, 1)) = 0.5
        _RimSmooth ("Rim Smooth", Range(0, 1)) = 0.1

    }

    SubShader
    {
        Pass
        {
            Tags
            {
                "LightMode" = "ForwardBase"
            }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase

            #include "UnityCg.cginc"
            #include "Lighting.cginc"
            #include "AutoLight.cginc"

            half _Specular;
            fixed _Gloss;

            fixed4 _Color;
            fixed4 _HColor;
            fixed4 _SColor;
            
            sampler2D _MainTex;
            sampler2D _ShadowTex;
            sampler2D _FalloffSampler;
            sampler2D _RimLightSampler;

            
            float _RampThreshold;
            float _RampSmooth;
            float _ToonSteps;
            
            float _SpecSmooth;
            fixed _Shininess;
            
            fixed4 _RimColor;
            fixed _RimThreshold;
            float _RimSmooth;

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 worldNormal : TEXCOORD1;
                float4 worldPos: TEXCOORD2;
                SHADOW_COORDS(3)
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                TRANSFER_SHADOW(o);
                return o;
            }



            float linearstep(float min, float max, float t)
            {
                return saturate((t - min) / (max - min));
            }


    


            fixed4 LightingToon(half3 L, half3 V, half3 N, fixed4 shadow, fixed4 albedo, half Specular, fixed Gloss, half atten)
            {
                half3 H = normalize(L + V);
                
                float ndl = max(0, dot(N, L));
                float ndh = max(0, dot(N, H));
                float ndv = max(0, dot(N, V));
                
                // multi steps
                float diff = smoothstep(_RampThreshold - ndl, _RampThreshold + ndl, ndl);
                float interval = 1 / _ToonSteps;
                float level = round(diff * _ToonSteps) / _ToonSteps;
                float ramp ;
                if (_RampSmooth == 1)
                {
                    ramp = interval * linearstep(level - _RampSmooth * interval * 0.5, level + _RampSmooth * interval * 0.5, diff) + level - interval;
                }
                else
                {
                    ramp = interval * smoothstep(level - _RampSmooth * interval * 0.5, level + _RampSmooth * interval * 0.5, diff) + level - interval;
                }
                ramp = max(0, ramp);
                ramp *= atten;
                
                fixed4 color;
                color = lerp(shadow, albedo, ramp); 

                _SColor = lerp(_HColor, _SColor, _SColor.a);
                float3 rampColor = lerp(_SColor.rgb, _HColor.rgb, ramp);
                
                // specular
                float spec = pow(ndh, Specular * 128.0) * Gloss;
                spec *= atten;
                spec = smoothstep(0.5 - _SpecSmooth * 0.5, 0.5 + _SpecSmooth * 0.5, spec);
                
                // rim
                float rim = (1.0 - ndv) * ndl;
                rim *= atten;
                rim = smoothstep(_RimThreshold - _RimSmooth * 0.5, _RimThreshold + _RimSmooth * 0.5, rim);
                
                fixed3 lightColor = _LightColor0.rgb;
                
                
                fixed3 diffuse = albedo.rgb * lightColor * rampColor;
                fixed3 specular = _SpecColor.rgb * lightColor * spec;
                fixed3 rimColor = _RimColor.rgb * lightColor * _RimColor.a * rim;
                
                color.rgb = color.rgb + diffuse + specular + rimColor;
                color.a = albedo.a;
                return color;
            }








            fixed4 frag(v2f i) : SV_TARGET
            {

                float3 L = normalize(UnityWorldSpaceLightDir(i.worldPos.xyz));
                float3 V = normalize(UnityWorldSpaceViewDir(i.worldPos.xyz));
                float3 N = normalize(i.worldNormal);

                fixed4 albedo = tex2D(_MainTex, i.uv);
                fixed4 shadow = tex2D(_ShadowTex, i.uv);
                float atten = SHADOW_ATTENUATION(i);


                // Falloff
                float ndolv = dot(N, V );
                float falloffU = clamp( 1 - abs( ndolv ), 0.02, 0.98 );
                float4 falloffSamplerColor = tex2D( _FalloffSampler, float2( falloffU, 0.25f ) );
                float3 combinedColor = lerp(albedo.rgb, albedo.rgb * albedo.rgb, falloffSamplerColor.a );

                // Rimlight
                float rimlightDot = saturate( 0.5 * ( dot(N, L) + 1.0 ) );
                falloffU = saturate( rimlightDot * falloffU );
                falloffU = tex2D( _RimLightSampler, float2( falloffU, 0.25f ) ).r;
                float3 lightColor = albedo.rgb * 0.5;
                combinedColor += falloffU * lightColor;

                
               // fixed4 col = LightingToon(L, V, N, shadow, fixed4(combinedColor, albedo.a), atten);

                fixed4 col = LightingToon(L, V, N, shadow, fixed4(combinedColor * _Color.rgb, albedo.a * _Color.a), _Shininess, albedo.a, atten);

    


                return col;
            }

            ENDCG
        }

        //------------------------------------------
        // outline-轮廓Pass
        //------------------------------------------
        Pass
        {
            Cull Front
            ZTest Less


            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            //#include "CharaOutline.cg"


            // Material parameters
            float4 _Color;
            float4 _LightColor0;
            float _EdgeThickness = 1.0;
            float4 _MainTex_ST;

            // Textures
            sampler2D _MainTex;

            // Structure from vertex shader to fragment shader
            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
            };

            // Float types
            #define float_t  half
            #define float2_t half2
            #define float3_t half3
            #define float4_t half4

            // Outline thickness multiplier
            #define INV_EDGE_THICKNESS_DIVISOR 0.00285
            // Outline color parameters
            #define SATURATION_FACTOR 0.6
            #define BRIGHTNESS_FACTOR 0.8

            // Vertex shader
            v2f vert( appdata_base v )
            {
                v2f o;
                o.uv = TRANSFORM_TEX( v.texcoord.xy, _MainTex );

                half4 projSpacePos = UnityObjectToClipPos( v.vertex );
                half4 projSpaceNormal = normalize( UnityObjectToClipPos( half4( v.normal, 0 ) ) );
                half4 scaledNormal = _EdgeThickness * INV_EDGE_THICKNESS_DIVISOR * projSpaceNormal; // * projSpacePos.w;

                scaledNormal.z += 0.00001;
                o.pos = projSpacePos + scaledNormal;

                return o;
            }

            // Fragment shader
            float4 frag( v2f i ) : COLOR
            {
                float4_t diffuseMapColor = tex2D( _MainTex, i.uv );

                float_t maxChan = max( max( diffuseMapColor.r, diffuseMapColor.g ), diffuseMapColor.b );
                float4_t newMapColor = diffuseMapColor;

                maxChan -= ( 1.0 / 255.0 );
                float3_t lerpVals = saturate( ( newMapColor.rgb - float3( maxChan, maxChan, maxChan ) ) * 255.0 );
                newMapColor.rgb = lerp( SATURATION_FACTOR * newMapColor.rgb, newMapColor.rgb, lerpVals );
                
                return float4( BRIGHTNESS_FACTOR * newMapColor.rgb * diffuseMapColor.rgb, diffuseMapColor.a ) * _Color * _LightColor0; 
            }

            ENDCG
        }

    }

    Fallback "VertexLit"
    
}